#ifndef HASHACTIVITYBUFFEREDOUTPUTBOX_H_JM_20130208
#define HASHACTIVITYBUFFEREDOUTPUTBOX_H_JM_20130208
/// @file HashActivityBufferedOutputBox.h 
/// Bazova trieda pre aktivity, ktore potrebuju bufferovat vystup 
/// (tj. nepoznajy velkost vystupu).

// ##
#include "../../BufferedOutputBox.h"
#include "../HashActivity.h"
// ## bobox
#include <bobox_box.hpp>
#include <bobox_types.hpp>
// ## c++
#include <sstream>
#include <iostream>

#include "../../BoxProfiler.h"

namespace jm4bbx {

	/** Sablona bazovej triedy pre logiku db operacie resp. hashovaciu aktivitu 
	* s bufferovanym vystupom. Aktivita sa vykonava nad hasovacou tabulkou 
	* pre jeden operand db operacie nad relaciami R a S (jedna relacia je uz 
	* zahesovana v tabulke). 
	*  
	* Trieda poskytuje sluzby prijimania dat, vyhladania spravnych dvojic podla 
	* hashu a odosielanie vysledkov pre odvodenu triedu, ktora implemtuje logiku 
	* spracovania konkretnej operacie (rozdiel, join, prienik ...). 
	*  
	*  Odvodenie triedy potrebuju implementovat rozhranie {@link HashActivity}, 
	*  ktore im umoznuje postupne spracovat vsetky data z nezaheshovaneho 
	*  operandu resp. relacie. 
	*  
	*  Naviac box poskytuje schpnosti bufferovaneho vystup a teda potomok len 
	*  vklada data na vystup pomocou {@link #addOutputData} a o nic dalsie sa 
	*  nestara.
	*  
	*  Veskeru logiku ohladom alokacie priestoru pre vysledky a ich odosielanie
	*  je uz vyriesene a odvodene triedy sa o to nemusia starat. 
	*  HashActivityBox v pripade uplneho naplnenia odosielanej spravy datami 
	*  prerusi spracovanie a data odosle. Tento proces je vsak skryty 
	*  a potomok to nezisti.
	*  
	* @tparam hashBoxType Poskytuje typove informacie o hashovani vykonanom 
	* inym boxom v predoslom vypocte a hlavne spristupnuje hashovaciu tabulku.
	* 
	**/
	template<class hashBoxType, class HashHandlerType>
	class  HashActivityBufferedOutputBox :  public HashActivity<hashBoxType>, 
		public BufferedOneOutputBox<BinaryOperationResultIndexType> {

	public:

		static const  groupType INPUT_GROUP;
		static const  groupType OUTPUT_GROUP;	
		static const  columnType INPUT_COLUMN;
		static const  columnType OUTPUT_COLUMN;
		static const  inType IN_ARC;
		static const  outType OUT_ARC;


		HashActivityBufferedOutputBox(const BoxParamPack& p) 
			: HashActivity(p),
			BufferedOneOutputBox(p, OUTPUT_GROUP, OUTPUT_COLUMN, OUT_ARC),
			activityHandler_(this, p) { }

		virtual HashActivityHanndlerType* getHashActivityHandler() override {
			return &activityHandler_;
		}

		virtual void initImpl() {

			add_group(INPUT_GROUP, INPUT_COLUMN, 
				get_input_descriptors(IN_ARC));

			add_group(OUTPUT_GROUP, OUTPUT_COLUMN, 
				get_output_descriptors(OUT_ARC));

			initBufferedOutputs();
			wait4Receive();
		}
		
		GroupPtr ig_; 
		JM_USE_EXPLICIT_LOGGER(Step2Tracer)
			
		JM_USE_SUM_BOX_PROFILER

		virtual void syncMachEtwas() {
			JM_SUM_BOX_PROFILER_START
			if (!ig_)
				ig_ = getGroupPtr(INPUT_GROUP);
			doHashActivity(ig_);
			sendOutputData();

			// Pokial je vstup spracovany cely ...
			if (!(ig_->getReadPosition() < ig_->getReadEnd())) {
				// a vystup je uz cely aj odoslany -> koniec prace boxu.
				if (isOutputEmpty()) {
					send_poisoned(OUT_ARC); // Aby ciel vedel ze je hotovo!!!
					sendSignalsOut(true);
					wait4Receive();
				} 
			}
			JM_SUM_BOX_PROFILER_STOP(Step2Tracer)
			// V opacnom pripade nerobim nic a necham box opat naplanovat 
			// nech dokonci svoju cinnost.
		}

		virtual policyType* getData() override {
			return get_data<policyType>(INPUT_COLUMN);
		}

		virtual bool stopActivity() override { 
			// Pokial je vystup plny tak prerusim spracovanie a potom sa opat 
			// spusti (opatovnym naplanovaniem boxu).
			return isOutputFull();
		}


	private:	
		HashHandlerType activityHandler_;
		/// Zahajenie cakania na vstup.
		void wait4Receive() {
			receive(IN_ARC, INPUT_GROUP);
		}

	};


	template<class hashBoxType, class HashHandlerType>
	const  outType HashActivityBufferedOutputBox<hashBoxType, 
		HashHandlerType>::OUT_ARC = outType(0);

	template<class hashBoxType, class HashHandlerType>
	const  inType HashActivityBufferedOutputBox<hashBoxType, 
		HashHandlerType>::IN_ARC = inType(0);

	template<class hashBoxType, class HashHandlerType>
	const  columnType HashActivityBufferedOutputBox<hashBoxType, 
		HashHandlerType>::OUTPUT_COLUMN = columnType(1);

	template<class hashBoxType, class HashHandlerType>
	const  columnType HashActivityBufferedOutputBox<hashBoxType, 
		HashHandlerType>::INPUT_COLUMN = columnType(0);

	template<class hashBoxType, class HashHandlerType>
	const  groupType HashActivityBufferedOutputBox<hashBoxType, 
		HashHandlerType>::OUTPUT_GROUP = groupType(1);

	template<class hashBoxType, class HashHandlerType>
	const  groupType HashActivityBufferedOutputBox<hashBoxType, 
		HashHandlerType>::INPUT_GROUP = groupType(0);

} // namespace jm4bbx


#endif
